//
//  CoreData+Extension.swift
//  zhengwutong
//
//  Created by wangshuguan on 16/8/18.
//  Copyright © 2016年 wangshuguan. All rights reserved.
//

import UIKit
import SwiftyJSON
import MagicalRecord
public let debugCoreData = true
public protocol INSManagedObject: class, NSFetchRequestResult{
    /// 属性名
    static var properties:[String]{get}
    /// 属性类型
    static var propertieTypes:[String:String]{get}
    /// 多主键，无主键时返回空数组
    static var primaryKeys:[String]{get}
}
public extension NSManagedObjectContext{
    static func defaultContext()->NSManagedObjectContext{
        return NSManagedObjectContext.mr_default()
    }
}
public extension INSManagedObject where Self:NSManagedObject{
    /// 寻找已存在的对象，如果找不到就创建一个新的对象
    ///
    /// - Parameters:
    ///   - localContext: 委托上下文
    ///   - predicate: 筛选条件
    /// - Returns: 当前对象
    static func findOrCreate(inContext localContext:NSManagedObjectContext = .defaultContext(),predicate: NSPredicate)->Self?{
        guard let obj = mr_findFirst(with: predicate, in: localContext) else {
            return mr_createEntity(in: localContext)
        }
        return obj
        
    }
    /// 类名
    static var className :String{
        get{
            return NSStringFromClass(self.classForCoder()).components(separatedBy: ".").last!
        }
    }
    /// 从上下文中找到某个数据
    ///
    /// - Parameters:
    ///   - context: 托管上下文
    ///   - limit: 搜索限制
    ///   - predicate: 搜索条件
    ///   - sort: 排序情况
    /// - Returns: 当前的对象
    static func findAll(context:NSManagedObjectContext = .defaultContext(),limit:Int = -1,predicate:NSPredicate? = nil,sort:[(String,Bool)] = primaryKeys.map({($0,true)})) -> [Self]? {
        let request:NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: self.className)
        request.sortDescriptors = sort.map { (key,value) -> NSSortDescriptor in
            return NSSortDescriptor(key: key, ascending: value)
        }
        
        if limit >= 0 {
            request.fetchLimit = limit
        }
        request.predicate = predicate
        var results:[Self]?
        do {
            results = try context.fetch(request) as? [Self]
        }catch{
            print("\(error)")
        }
        return results
    }
    /// 通过primarykey获取对象
    ///
    /// - Parameters:
    ///   - id: 主键的值
    ///   - context: 要搜索的上下文
    /// - Returns: 获得的对象
    static func model(_ ids:[String], in context:NSManagedObjectContext = .defaultContext())->Self?{
        
        guard self.primaryKeys.isNotEmpty else{
            print("查询失败，无主键")
            return nil
        }
        guard self.primaryKeys.count == ids.count else{
            print("查询失败，主键数量不匹配")
            return nil
        }
        var strs:[String] = []
        for i in 0 ..< self.primaryKeys.count{
            strs.append("\(self.primaryKeys[i]) == '\(ids[i])'")
        }
        let str = strs.joined(separator: " and ")
        return mr_findFirst(with: NSPredicate(format: str, argumentArray: nil), in: context)
    }
    /// 清空数据库并保存
    ///
    /// - Parameter context: 上下文
    static func removeAllAndSave(in context:NSManagedObjectContext = .defaultContext()){
        _ = mr_truncateAll(in: context)
    }
    /// 通过JSON删除其中一个对象并保存
    ///
    /// - Parameters:
    ///   - json: 要删除的json
    ///   - context: 要处理的上下文，默认当前上下文
    static func removeAndSave(json:JSON,in context:NSManagedObjectContext = .defaultContext()){
        guard self.primaryKeys.isNotEmpty else{
            print("移除失败，无主键")
            return
        }
        let str = self.primaryKeys.map({"\($0) == '\(json[$0].stringValue)'"}).joined(separator: " and ")
        _ = mr_deleteAll(matching: NSPredicate(format: str, argumentArray: nil), in: context)
    }
    /// 通过JSON删除其中一个对象（需要外界saveblock）
    ///
    /// - Parameters:
    ///   - json: 要删除的json
    ///   - context: 要处理的上下文，默认当前上下文
    static func remove(json:JSON,in context:NSManagedObjectContext = .defaultContext()){
        guard self.primaryKeys.isNotEmpty else{
            print("移除失败，无主键")
            return
        }
        let str = self.primaryKeys.map({"\($0) == '\(json[$0].stringValue)'"}).joined(separator: " and ")
        _ = mr_deleteAll(matching: NSPredicate(format: str, argumentArray: nil), in: context)
    }
    /// 通过主键删除其中一个对象
    static func removeAndSave(ids:[String],in context:NSManagedObjectContext = .defaultContext()){
        guard self.primaryKeys.isNotEmpty else{
            print("移除失败，无主键")
            return
        }
        guard self.primaryKeys.count == ids.count else{
            print("移除失败，主键数量不匹配")
            return
        }
        var strs:[String] = []
        for i in 0 ..< self.primaryKeys.count{
            strs.append("\(self.primaryKeys[i]) == '\(ids[i])'")
        }
        let str = strs.joined(separator: " and ")
        _ = mr_deleteAll(matching: NSPredicate(format: str, argumentArray: nil), in: context)
    }
    /// 转换为字典
    var dictionary:[String:Any]{
        get{
            var dic:[String:Any] = [:]
            for key in Self.properties {
                dic[key] = value(forKey: key)
            }
            return dic
        }
    }
    /// 转换为json
    var json:JSON{
        get{
            return JSON(self.dictionary)
        }
    }
    /// 生成或替换对象
    ///
    /// - Parameters:
    ///   - json: 要添加的对象
    ///   - inContext: 目标上下文
    /// - Returns: 已生成的对象
    static func createOrReplace(json:JSON,inContext: NSManagedObjectContext)->Self?{
        var obj:Self?
        if self.primaryKeys.isNotEmpty{
            let str = self.primaryKeys.map({"\($0) == '\(json[$0].stringValue)'"}).joined(separator: " and ")
            let predicate = NSPredicate(format: str, argumentArray: nil)
            obj = findOrCreate(inContext: inContext, predicate: predicate)
        }else{
            obj = mr_createEntity(in: inContext)
        }
        
        for s in properties {
            if json[s].type == .array{
                obj?.setValue((json[s].arrayObject as? [String])?.joined(separator: ","), forKey: s)
            }else{
                if propertieTypes[s] == "Int"{
                    obj?.setValue(json[s].int64Value, forKey: s)
                }else{
                    obj?.setValue(json[s].stringValue, forKey: s)
                }
            }
        }
        return obj
    }
    /// 生成或替换一堆对象
    ///
    /// - Parameters:
    ///   - jsons: 一堆对象数组
    ///   - inContext: 目标上下文
    /// - Returns:  已生成的对象，数组
    static func createOrReplace(jsons:[JSON],inContext: NSManagedObjectContext)->[Self]{
        var arr = [Self]()
        for json in jsons {
            if let obj = createOrReplace(json: json, inContext: inContext){
                arr.append(obj)
            }
        }
        return arr
    }
    /// 生成或替换一堆对象
    ///
    /// - Parameters:
    ///   - jsons: 一堆对象
    ///   - inContext: 目标上下文
    /// - Returns:  已生成的对象，数组
    static func createOrReplace(jsons:JSON,inContext: NSManagedObjectContext)->[Self]{
        var arr = [Self]()
        if jsons.type == Type.array {
            for json in jsons.array! {
                if let obj = createOrReplace(json: json, inContext: inContext){
                    arr.append(obj)
                }
            }
        }else if jsons.type == Type.dictionary{
            if let obj = createOrReplace(json: jsons, inContext: inContext){
                arr.append(obj)
            }
        }
        return arr
    }
    /// 仅仅生成一堆对象
    ///
    /// - Parameters:
    ///   - jsons: 一堆对象数组
    ///   - inContext: 目标上下文
    /// - Returns:  已生成的对象，数组
    static func create(jsons:[JSON],inContext: NSManagedObjectContext)->[Self]{
        var arr = [Self]()
        for json in jsons {
            if let obj = create(json: json, inContext: inContext){
                arr.append(obj)
            }
        }
        return arr
    }
    /// 仅仅生成一堆对象
    ///
    /// - Parameters:
    ///   - jsons: 一堆对象
    ///   - inContext: 目标上下文
    /// - Returns:  已生成的对象，数组
    static func create(jsons:JSON,inContext: NSManagedObjectContext)->[Self]{
        var arr = [Self]()
        if jsons.type == Type.array {
            for json in jsons.array! {
                if let obj = create(json: json, inContext: inContext){
                    arr.append(obj)
                }
            }
        }else if jsons.type == Type.dictionary{
            if let obj = create(json: jsons, inContext: inContext){
                arr.append(obj)
            }
        }
        return arr
    }
    /// 仅仅生成对象
    ///
    /// - Parameters:
    ///   - json: 要添加的对象
    ///   - inContext: 目标上下文
    /// - Returns: 已生成的对象
    static func create(json:JSON,inContext: NSManagedObjectContext)->Self?{
        let obj:Self? = mr_createEntity(in: inContext)
        for s in properties {
            if json[s].type == .array{
                obj?.setValue((json[s].arrayObject as? [String])?.joined(separator: ","), forKey: s)
            }else{
                if propertieTypes[s] == "Int"{
                    obj?.setValue(json[s].int64Value, forKey: s)
                }else{
                    obj?.setValue(json[s].stringValue, forKey: s)
                }
            }
        }
        return obj
    }
}

extension NSManagedObject {
    /// 将模型从指定上下文里删掉
    ///
    /// - Parameter localContext: 指定上下文
    /// - Returns: 删除结果
    public func remove(inContext localContext:NSManagedObjectContext = .defaultContext()) -> Bool {
        return mr_deleteEntity(in: localContext)
    }
}
extension Array where Element == NSManagedObject{
    /// 将模型对象删除
    func removeAllModels(inContext localContext:NSManagedObjectContext = .defaultContext()) {
        for x in self {
            _ = x.remove(inContext: localContext)
        }
    }
}
extension Array where Element : NSManagedObject,Element:INSManagedObject{
    func toJSON() -> [JSON] {
        var arr:[JSON] = []
        for obj in self{
            arr.append(obj.json)
        }
        return arr
    }
}
